iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Security

你的程式真的安全嗎?從資安的角度做 code review系列 第 7

C - stack buffer overflow(記憶體損壞:堆疊溢位)

  • 分享至 

  • xImage
  •  

雖遲但到!
下方程式碼片段全部都是擷取自 Secure Code Warrior 線上安全程式培訓平台,因為練習互動時的題目多半不會只有單一個檔案,可能涉及多個檔案、資料夾及多處地方修改,因此我的文章主要是針對最主要的區塊做修改及說明,若有不好理解的地方非常抱歉也還請見諒,也可以實際上去 Secure Code Warrior 玩玩看,搭配著互動,會更有感的學習哦~

C - stack buffer overflow(記憶體損壞:堆疊溢位)

  • 形成原因:呼叫堆疊指標超過堆疊界線,但使用者仍想繼續使用更多空間時
  • 後果:當電腦記憶體呼叫堆疊區域中的緩衝區,如果未實現適當的邊界檢查,或使用不安全的函數(如sprintf、fgets 等),這些函數不需要目標大小限制,則可能會寫入目標緩衝區後的堆疊內存,從而允許攻擊者改變程式的正常行為
  • 實例:假設我們有一個程式,提供字串複製到一個10位元組長的字串緩衝區中,使用者輸入一個13字元的字串,多出來的3個字元超出緩衝區導致程式毀損
#include <sting.h>

void f(char* s){
    char buffer[10];
    sttcpy(buffer,s);
}
void main(void){
    f("0123456789xyz");
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台
  • 解決方法:
    • 手動或使用自動化工具檢查程式碼
    • 如果資料過長或是資料型態不符、包含垃圾字元,則處理輸入內容
    • 使用能夠識別緩衝區溢位的編譯器
    • 將記憶體的某些部分標記為不可執行堆疊
    • 部署程式在不可執行堆疊的系統上,像是windows 2003 sp1 或 linux 2.6.8以上版本
    • 使用不直接存取記憶體的高階程式語言

第一題

錯誤區塊

char line[ 1048576 ] = {0};
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:
堆疊大小通常是有限的(例如,在Windows下,預設為1 Mb),因此試圖在堆疊上分配過大的緩衝區將導致堆疊溢位,這將導致應用程式崩潰。

主要修正方法

把原本程式碼刪掉改成直接宣告line這個空變數(不宣告大小和不賦值),後面判斷直接用if(line!=empty)

解釋:用預設的系統堆疊大小就好,不要試圖改變系統記憶體大小(沒截到就跳掉了qq)

第二題

錯誤區塊

const unsigned maxL = 20;
char value[7][maxL];
sscanf(stringFromFile.c_str(),"%[^_]_%[^_]_%[^_]_%[^_]_%[^_]_%[^_]_%s",
      value[0], value[1], value[2], value[3], value[4], value[5], value[6]);
for (unsigned i=0;i<DEFAULT_PARAMS_CNT;++i)
{
  trackValues.push_back(value[i]);
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:宣告固定大小的陣列並使用不安全的函式向其寫入資料,為基於堆疊的緩衝區溢位創造了條件。資料可以寫入宣告的陣列之外,還可能導致其程式損壞、失敗或惡意程式碼執行。

主要修正方法

一樣把原本程式碼整段刪掉,不要宣告任何限制大小的變數

解釋:
又沒截到qq

第3題

錯誤區塊

return getNextUser( accounts, users );
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:可以使用遞歸方法讀取XML節點列表。但如果列表太長,在深度遞迴期間有達到堆疊溢位的危險可能性。

主要修正方法

原程式碼段落:

bool getNextUser( std::vector< Account >* accounts, MSXML::IXMLDOMNodeListPtr users )
{
	MSXML::IXMLDOMNodePtr user = users->nextNode();
	if( user == NULL )
	{
		return true;
	}
	Account account;
	bool isName = getNodeValue( user, "name", account.name );
	bool isLogin = getNodeValue( user, "login", account.login );
	bool isPassword = getNodeValue( user, "password", account.password );
	if( !isName || !isLogin || !isPassword )
	{
		return false;
	}
	accounts->push_back( account );
	// Retrieve the next user.
	return getNextUser( accounts, users );
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

刪掉,並將以下程式碼

// Retrieve all users.
if( getNextUser( &accounts, users ) == false )
{
    return false;
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

修改為:

MSXML::IXMLDOMNodePtr user;
while( ( user = users->nextNode() ) != NULL )
{
    Account account;
    bool isName = getNodeValue( user, "name", account.name );
    bool isLogin = getNodeValue( user, "login", account.login );
    bool isPassword = getNodeValue( user, "password", account.password );
    if( !isName || !isLogin || !isPassword )
    {
        return false;
    }
    accounts.push_back( account );
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:
堆疊溢位通常發生在非常深或無界遞迴的情況下。需要避免深度遞迴呼叫,或應用其他編碼方式來避免可能出現的麻煩。


上一篇
C - use-after-free (記憶體損壞:釋放後使用)
下一篇
C - SQL injection(注入缺陷:SQL 注入)
系列文
你的程式真的安全嗎?從資安的角度做 code review18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言